home *** CD-ROM | disk | FTP | other *** search
/ Magnum One / Magnum One (Mid-American Digital) (Disc Manufacturing).iso / d12 / masm.arc / PARCHK.ASM < prev    next >
Assembly Source File  |  1985-03-06  |  31KB  |  580 lines

  1.  
  2.     page        ,132
  3.     title  PARCHK.ASM -- Replacement for IBM-PC ROM BIOS parity error routines
  4. ;*****************************************************************************
  5. ;*
  6. ;* copyright(C) 1984    Skip Gilbrech (CIS 71445,534)
  7. ;*                      90 Lexington Ave. #10-G
  8. ;*                      New York, NY 10016
  9. ;*                      212-685-0551
  10. ;*
  11. ;* This program may be freely copied/altered for any non-commercial
  12. ;* purpose but may not be sold or used in any way as part of any
  13. ;* profit-making venture without permission of the author.
  14. ;*
  15. ;* author = skip gilbrech
  16. ;* date written = 02/19/84
  17. ;*
  18. ;* environment:
  19. ;*  system = ibm pc (dos 2.0 - but should work on any version)
  20. ;*  processor = microsoft 8086 macro assembler
  21. ;*
  22. ;* USAGE: PARCHK /R (or) /D
  23. ;* /R = Report all errors which occur
  24. ;* /D = Disable reporting after an error
  25. ;*
  26. ;* PARCHK is a resident program which replaces the ibm pc rom-bios NMI
  27. ;* (non-maskable interrupt) handler.
  28. ;*
  29. ;* It will report any memory parity errors to the operator, but will allow
  30. ;* the system to continue running.  An installation option lets you choose
  31. ;* whether or not to receive continued reports after the first error for
  32. ;* a particular channel (system memory or i/o channel).  Regardless of the
  33. ;* option chosen, however, the first error for each channel will always be
  34. ;* reported.
  35. ;* 
  36. ;* I wrote PARCHK mostly because of the frustration I felt a few days ago
  37. ;* when the message 'PARITY CHECK 2' appeared suddenly on my pc's screen.
  38. ;* I had seen the message a couple of times before, but never at a time
  39. ;* like this:  The machine contained over 3 hours of unsaved work, and I
  40. ;* knew there was not a thing I could do about it, since the parity error
  41. ;* handler in the rom-bios simply disables interrupts and issues a HLT
  42. ;* instruction to the cpu.
  43. ;*
  44. ;* I have also read a number of messages on the Compuserve IBM-PC SIG
  45. ;* which indicate that I'm not the only one to have had this experience.
  46. ;* 
  47. ;* IBM's approach in the rom-bios makes some sense.  The condition of
  48. ;* system ram is unknown following a parity error, and continued operation
  49. ;* MIGHT result in all sorts of horrible consequences, i.e., hopelessly
  50. ;* corrupted data on disk, etc.
  51. ;*
  52. ;* On my system, though, memory parity errors have been extremely rare,
  53. ;* and have probably resulted from a slight glitch on the power line,
  54. ;* static, etc.  I really have no idea what would have happened if I
  55. ;* had been able to continue operation in those cases.  However, I have
  56. ;* crashed the system often enough (most of the time probably executing
  57. ;* random data or instructions somewhere) to have some confidence that the
  58. ;* most likely, if not the only possible, outcome of a processor gone wild
  59. ;* is simply a dead machine, i.e. interrupt vectors wiped out, etc., which
  60. ;* must be powered-down and up.
  61. ;*
  62. ;* So, for me, the risks of continued operation -- at least until important
  63. ;* data in ram are saved -- seem relatively small when balanced against
  64. ;* the CERTAINTY of lost data when the rom-bios routine gets control:  If
  65. ;* data HAS been corrupted, at least there remains the chance of later
  66. ;* being able to examine and possibly fix it.
  67. ;*
  68. ;* Continued operation still DOES represent a risk, however, especially
  69. ;* if parity errors occur often, since that probably indicates a serious
  70. ;* hardware problem somewhere in the system.
  71. ;*
  72. ;* If you don't want to take that risk, please don't use this program,
  73. ;* as I can't, of course, take responsibility for any damage, real or
  74. ;* otherwise, it may cause.
  75. ;*
  76. ;* On the other hand, if PARCHK is ever responsible for saving a multi-
  77. ;* million dollar oil deal which would otherwise have fallen victim to
  78. ;* an unruly parity bit......  (suffice it to say that I would deem it
  79. ;* an honor to allow you to express your gratitude)
  80. ;* 
  81. ;* The resident part of this code, by the way, uses up a little over 1K
  82. ;* of ram.  Most of that space is taken up by routines which save the
  83. ;* current screen, write the error message, and then restore the screen.
  84. ;* I made no particular effort to make that code as compact as possible,
  85. ;* so, if space is at a premium, and/or you like doing such things, please
  86. ;* feel free to squeeze and optimize to your heart's content...  As an
  87. ;* alternative, if you don't mind junk on your screen, it would be fairly
  88. ;* easy to replace most of the error message code with a short routine which
  89. ;* uses the rom-bios 'write teletype' function to print a message, but
  90. ;* doesn't waste any memory by saving the screen.  It's probably best not
  91. ;* to use dos functions here, since a parity error can be reported at any
  92. ;* time, even with interrupts disabled and/or while in the middle of a dos
  93. ;* routine -- and pc/ms-dos is notoriously non-reentrant.
  94. ;*
  95. ;**************************************************************************
  96.     page
  97. ;**************************************************************************
  98. ;*
  99. ;*      constants
  100. ;*
  101. ;**************************************************************************
  102. ; general equates:
  103. false           equ     0
  104. true            equ     not false
  105. cr              equ     0dh     ; carriage return
  106. lf              equ     0ah     ; line feed
  107. bell            equ     7       ; ascii bell
  108. spc             equ     ' '     ; ascii space, blank
  109. tab             equ     9       ; ascii horizontal tab
  110. ; program equates:
  111. dosint          equ     21h     ; interrupt number for dos functions
  112. prt_str         equ     9       ; dos print string function
  113. get_vers        equ     30h     ; dos get version number function
  114. get_int_vec     equ     35h     ; dos 2.0 get interrupt vector function
  115. set_int_vec     equ     25h     ; dos set interrupt vector function
  116. vidint          equ     10h     ; bios video interrupt number
  117. vid_state       equ     15      ; bios - get video state
  118. read_curs_pos   equ     3       ; bios - read cursor position
  119. set_curs_pos    equ     2       ; bios - set cursor position
  120. set_curs_type   equ     1       ; bios - set cursor type
  121. write_teletype  equ     14      ; bios - write teletype to display
  122. read_ac         equ     8       ; bios - read att/char at curs. position
  123. write_ac        equ     9       ; bios - write att/char at curs. position
  124. disp_row        equ     10      ; row to display error msg
  125. disp_col        equ     25      ; col to display error msg
  126. num_lines       equ     3       ; number of text lines to display
  127. normal          equ     7       ; normal (white on black) vid. attrib.
  128. reverse_blink   equ     0f0h    ; reverse-video blinking vid. attrib.
  129. reverse         equ     70h     ; reverse-video (no blink)
  130. ; hardware specific equates:
  131. port_a          equ     60h     ; system board 8255 port a address
  132. port_b          equ     61h     ; system board 8255 port b address
  133. port_c          equ     62h     ; system board 8255 port c address
  134. par_err_mask    equ     0c0h    ; mask to test for any parity error
  135. par_ch1_mask    equ     10000000b ; mask to test for system board parity error
  136. par_ch2_mask    equ     01000000b ; mask to test for i/o channel parity error
  137. disa_ch1_mask   equ     00010000b ; mask to disable system board parity checking
  138. enab_ch1_mask   equ     11101111b ; mask to enable system board parity checking
  139. disa_ch2_mask   equ     00100000b ; mask to disable i/o channel parity checking
  140. enab_ch2_mask   equ     11011111b ; mask to enable i/o channel parity checking
  141. nmi_int_no      equ     2       ; NMI interrupt number
  142. nmi_port        equ     0a0h    ; NMI control port
  143. enable_nmi      equ     80h     ; value to output to enable NMI
  144. disable_nmi     equ     0       ; value to output to disable NMI
  145. ;**************************************************************************
  146. int_vecs        segment at 0
  147. int_vecs        ends
  148.     page
  149. ;**************************************************************************
  150. cseg    segment
  151.         assume cs:cseg,ds:cseg
  152.         org     80h                     ; for processing command line parms.
  153. cmd_ct  label   byte                    ; number of chars. in command line
  154.         org     100h                    ; for .COM file
  155. entry:
  156.         jmp     init                    ; ck for residency, init if not resident
  157. reenable_flag   db      false           ; enable continued checking after error?
  158. active_page     db      ?               ; current active page
  159. curs_pos        dw      ?               ; current cursor position
  160. orig_nmi_int_vec dd     ?               ; pointer to orig. NMI service routine
  161. start_row_1     equ     $
  162. par_ch1_msg     db      " PARITY CHECK 1 (System Board) "
  163. length_row      equ     $ - offset start_row_1
  164. par_ch2_msg     db      " PARITY CHECK 2  (I/O channel) "
  165. msg_1           db      "  Parity error reporting for   "
  166. msg_1a          db      " this channel will be disabled "
  167. msg_1b          db      "  this channel will continue   "
  168. scn_storage     dw      (length_row * 5) dup (?) ; storage for current screen
  169.                                                  ; display
  170.     page
  171. ;**************************************************************************
  172. ;* This is the start of the new NMI interrupt handler code.
  173. ;*
  174. ;* 1. Check system board 8255 to determine if a parity error has occurred.
  175. ;* 2. If not, pass control to the original NMI vector.
  176. ;* 3. If a parity error has occurred:
  177. ;*    a. Disable the NMI temporarily.
  178. ;*    b. Determine which channel was affected and disable parity reporting.
  179. ;*    c. Determine whether error reporting will continue, depending on
  180. ;*       which installation option was selected.
  181. ;*    d. Print appropriate message and loop for about 10 seconds.
  182. ;*    e. Re-enable reporting on the error channel if the /R option was selected.
  183. ;*    f. Re-enable the NMI.
  184. nmi_int_hdlr proc
  185.         pushf           ; if we jump to orig. vector, arrive in same condition
  186.         push    ax                      ;
  187.         in      al,port_c               ; read 8255 port
  188.         test    al,par_err_mask         ; has a parity error occurred?
  189.         jnz     nmi_1                   ; yes, jump to error routine
  190.         pop     ax                      ; else, restore entering machine state
  191.         popf                            ;
  192.         jmp     cs:orig_nmi_int_vec     ; and pass control to original vector
  193. nmi_1:
  194.         push    ax                      ; save value read from port c
  195.         mov     al,disable_nmi          ; disable NMI
  196.         out     nmi_port,al             ;
  197.         pop     ax                      ; restore port c value
  198.         sti                             ; allow further interrupts
  199.         push    bx                      ; save possibly affected registers
  200.         push    cx                      ;
  201.         push    dx                      ;
  202.         push    si                      ;
  203.         push    di                      ;
  204.         push    bp                      ;
  205.         push    ds                      ;
  206.         push    es                      ;
  207.         push    ax                      ; save port value again
  208.         mov     ax,cs                   ; set DS and ES to CS
  209.         mov     ds,ax                   ;
  210.         mov     es,ax                   ;
  211.         call    save_screen             ; save contents of current display
  212.         pop     ax                      ; restore port value
  213.         test    al,par_ch2_mask         ; test for i/o channel error
  214.         in      al,port_b               ; get value at 8255 port b
  215.         jnz     nmi_2                   ; jump if i/o channel error
  216.         mov     ah,disa_ch1_mask        ; else, put planar disabling mask in AH
  217.         mov     si,offset par_ch1_msg   ; put adr of system board msg in SI
  218.         jmp     short nmi_3             ; and continue
  219. nmi_2:
  220.         mov     ah,disa_ch2_mask        ; put i/o channel disabling mask in AH
  221.         mov     si,offset par_ch2_msg   ; put adr of i/o channel msg in SI
  222. nmi_3:
  223.         or      al,ah                   ; turn on proper bit
  224.         out     port_b,al               ; disable appropriate channel to reset
  225.         push    ax                      ; save mask value in AH
  226.         mov     ax,offset msg_1         ; put adr of 2nd line of message in AX
  227.         mov     bx,offset msg_1a        ; put adr of 'remain disabled' msg in BX
  228.         cmp     reenable_flag,false     ; is continued checking desired?
  229.         pushf                           ; save result of comparison
  230.         je      nmi_4                   ; no, continue
  231.         mov     bx,offset msg_1b        ; else, put 'reenable' msg adr in BX
  232. nmi_4:
  233.         call    print_msg               ; display our message
  234. ; -- loop allow reading the message
  235.         mov     cx,15                   ; trying to hit 10 seconds...
  236. nmi_5:
  237.         mov     bx,cx                   ; save outer loop count
  238.         sub     cx,cx                   ; do each inner loop 65536 times
  239. nmi_6:
  240.         loop    nmi_6                   ; spin wheels...
  241. nmi_7:
  242.         loop    nmi_7                   ; ...
  243.         mov     cx,bx                   ; restore outer loop count
  244.         loop    nmi_5                   ; and spin some more until done...
  245.         call    restore_screen          ; restore original display
  246.         popf                            ; flags show if reenabling desired
  247.         pop     ax                      ; restore mask value in AH
  248.         je      nmi_8                   ; continue if reenabling not wanted
  249.         not     ah                      ; else, flip bits in AH
  250.         in      al,port_b               ; get 8255 port b value
  251.         and     al,ah                   ; turn masked bit off again
  252.         out     port_b,al               ; and reenable the channel
  253. nmi_8:
  254.         pop     es                      ; restore machine state
  255.         pop     ds                      ;
  256.         pop     bp                      ;
  257.         pop     di                      ;
  258.         pop     si                      ;
  259.         pop     dx                      ;
  260.         pop     cx                      ;
  261.         pop     bx                      ;
  262.         mov     al,enable_nmi           ; reenable NMI
  263.         out     nmi_port,al             ;
  264.         pop     ax                      ;
  265.         popf                            ;
  266.         iret
  267. nmi_int_hdlr endp
  268.     page
  269. ;**************************************************************************
  270. ; Save current contents of the portion of the screen we will overwrite.
  271. ; Also save the current active page and cursor position.
  272. ; Registers not preserved.
  273. save_screen     proc near
  274.                 mov     ah,vid_state            ; get active page
  275.         int     vidint                  ; bios video interrupt
  276.         mov     active_page,bh          ; store it for others..
  277.         mov     ah,read_curs_pos        ; get cursor position and type
  278.         int     vidint                  ;
  279.         mov     curs_pos,dx             ; store data
  280.         mov     dx,(disp_row * 256 + disp_col)  ; cursor at start of our msg
  281.         mov     cx,num_lines + 2        ; save enough for top & bot. blank
  282.                                         ;  lines, and our message
  283.         mov     di,offset scn_storage   ; point DI to buffer
  284. ss_1:
  285.         push    dx                      ; save cursor position
  286.         push    cx                      ; save outer loop count
  287.         mov     cx,length_row           ; get number of chars. per row
  288. ss_2:
  289.         push    di                      ; save buffer ptr
  290.         mov     ah,set_curs_pos         ; set cursor pos.
  291.         int     vidint                  ;
  292.         mov     ah,read_ac              ; get attr/char at curs. pos
  293.         int     vidint                  ;
  294.         pop     di                      ; restore buffer ptr.
  295.         stosw                           ; store attr/char in buffer
  296.         inc     dl                      ; bump DL to next column
  297.         loop    ss_2                    ; do for the entire row
  298.         pop     cx                      ; restore outer loop count
  299.         pop     dx                      ; restore cursor position
  300.         inc     dh                      ; bump DH to next row
  301.         loop    ss_1                    ; do for required number of rows
  302.         ret
  303. save_screen     endp
  304.     page
  305. ;**************************************************************************
  306. ; Restore original contents of the screen.
  307. ; Also restore the current cursor position.
  308. restore_screen  proc near
  309.         mov     bh,active_page          ; get active page in BH
  310.         mov     dx,(disp_row * 256 + disp_col)  ; cursor at start of our msg
  311.         mov     cx,num_lines + 2        ; restore amount saved...
  312.         mov     si,offset scn_storage   ; point DI to buffer
  313. rs_1:
  314.         push    dx                      ; save cursor pos.
  315.         push    cx                      ; save outer loop count
  316.         mov     cx,length_row           ; get number of chars. per row
  317.         push    si                      ; save buffer ptr
  318. rs_2:
  319.         mov     ah,set_curs_pos         ; set cursor pos.
  320.         int     vidint                  ;
  321.         pop     si                      ; restore buffer ptr
  322.         lodsw                           ; get the attr/char in AX, bump SI
  323.         push    si                      ; save it...
  324.         mov     bl,ah                   ; put attr. where bios wants it
  325.         mov     ah,write_ac             ; write attr/char at curs. pos
  326.         push    cx                      ; save row chars remaining
  327.         mov     cx,1                    ; tell bios to write 1 char.
  328.         int     vidint                  ;
  329.         pop     cx                      ; restore row chars remaining
  330.         inc     dl                      ; bump DL to next column
  331.         loop    rs_2                    ; do for the entire row
  332.         pop     si                      ; keep stack in order....
  333.         pop     cx                      ; restore outer loop count
  334.         pop     dx
  335.         inc     dh                      ; bump DH to next row
  336.         loop    rs_1                    ; do for required number of rows
  337.         mov     dx,curs_pos             ; restore original cursor pos
  338.         mov     ah,set_curs_pos         ;
  339.         int     vidint                  ;
  340.         ret
  341. restore_screen  endp
  342.     page
  343. ;**************************************************************************
  344. ; Print message to console
  345. ; 1st and last line blanks - start at current curs. pos.
  346. ; SI has adr. of 1st string, AX has second, and BX has third.
  347. print_msg       proc near
  348.         push    bx              ; push string addresses
  349.         push    ax              ;
  350.         push    si              ;
  351.         mov     al,bell         ; first put out a beep
  352.         mov     ah,write_teletype ;
  353.         int     vidint          ;
  354.         mov     bl,reverse_blink ; reverse-video blinking vid. attrib.
  355.         mov     bh,active_page  ; get active page in BH
  356.         mov     cx,length_row   ; length of a row
  357.         mov     dx,(disp_row * 256 + disp_col)  ; cursor at start of our msg
  358.         call    blank_line      ; put out the first blank line
  359.         pop     si              ; address of 1st line
  360.         call    char_line       ;
  361.         pop     si              ; ...2nd line
  362.         mov     bl,reverse      ; don't blink for the rest of msg
  363.         call    char_line       ;
  364.         pop     si              ; ...3rd line
  365.         call    char_line       ;
  366.         call    blank_line      ; ... and last blank line
  367.         mov     dx,curs_pos     ; restore original cursor pos
  368.         mov     ah,set_curs_pos ;
  369.         int     vidint          ;
  370.         ret
  371. blank_line:                     ; write CX blanks, bump row position
  372.         mov     ah,set_curs_pos ; set cursor pos.
  373.         int     vidint          ;
  374.         mov     ah,write_ac     ; write attr/char at curs. pos
  375.         mov     al,' '          ; write blanks
  376.         int     vidint          ;
  377.         inc     dh              ; bump row position
  378.         ret
  379. char_line:
  380. ; -- attrib. in BL, active page in BH, count in CX, starting pos. in DX
  381. ;    get chars. starting at DS:SI
  382.         push    cx                      ; save count of chars. in line
  383.         push    dx                      ; save starting curs. pos.
  384.         push    si                      ; save buffer ptr
  385. cl_1:
  386.         mov     ah,set_curs_pos         ; set cursor pos.
  387.         int     vidint                  ;
  388.         pop     si                      ; restore buffer ptr
  389.         lodsb                           ; get char. from message string in AL
  390.         push    si                      ; save bumped string ptr.
  391.         push    cx                      ; save chars. remaining in line
  392.         mov     cx,1                    ; so bios will write one char.
  393.         mov     ah,write_ac             ; write attr/char at curs. pos
  394.         int     vidint                  ;
  395.         pop     cx                      ; restore chars. remaining in line
  396.         inc     dl                      ; bump DL to next column
  397.         loop    cl_1                    ; do for the entire row
  398.         pop     si                      ; keep stack in order....
  399.         pop     dx                      ; restore starting curs. pos.
  400.         inc     dh                      ; bump DH to next row
  401.         pop     cx                      ; restore count of chars. in line
  402.         ret
  403. print_msg       endp
  404. ; -- This is the end of the code which will be made permanently resident.
  405. end_nmi_int_hdlr        equ     $
  406. len_nmi_int_hdlr        equ     (end_nmi_int_hdlr - nmi_int_hdlr)
  407.     page
  408. ;**************************************************************************
  409. install_msg     db cr,lf,"PARCHK (v 1.0) installed -- Copyright (C) 1984 Skip Gilbrech",cr,lf,'$'
  410. resident_msg    db cr,lf,bell,"PARCHK (v 1.0) already resident",cr,lf,'$'
  411. usage_msg       db cr,lf
  412. db "PARCHK (v 1.0) -- Copyright (C) 1984 Skip Gilbrech",cr,lf,cr,lf
  413. db "USAGE: PARCHK /R (or) /D",cr,lf
  414. db "/R = Report all errors which occur",cr,lf
  415. db "/D = Disable reporting after an error",cr,lf,cr,lf
  416. db "PARCHK replaces the ibm pc rom-bios NMI (non-maskable interrupt) handler.",cr,lf
  417. db "It will report any memory parity errors to the operator, but will allow",cr,lf
  418. db "the system to continue running.  An installation option lets you choose",cr,lf
  419. db "whether or not to receive continued reports after the first error for",cr,lf
  420. db "a particular channel (system memory or i/o channel).  Regardless of the",cr,lf
  421. db "option chosen, however, the first error for each channel will always be",cr,lf
  422. db "reported.  The source file, PARCHK.ASM, contains some cautions which",cr,lf
  423. db "you should read before using this program.",cr,lf,cr,lf,'$'
  424.     page
  425. ;**************************************************************************
  426. ;* Initialization procedure:
  427. ;*
  428. ;*      1. Check whether the routine is already resident by getting the current
  429. ;*         interrupt vector and checking whether our code is servicing it.
  430. ;*         If so, just print message and exit without installing
  431. ;*      2. Check command line to see if continued checking is wanted after
  432. ;*         error and set flag accordingly.  If no parms or unknown parms,
  433. ;*         print informational message and exit without installing.
  434. ;*      3. Otherwise, change vector to point to our handler, print installation
  435. ;*         message, and execute dos 'terminate but stay resident' interrupt,
  436. ;*         installing only the code which will actually be used.
  437. ;*
  438. ;* The idea, and much of the code, for the 'testresident' routine, came
  439. ;* from Tony A. Rhea's KEYSTAT program.  His copyright notice is reproduced
  440. ;* below:
  441. ;*
  442. ;*      KEYSTAT -- Copyright (C) 1983 Tony A. Rhea
  443. ;*      This program may be copied for non-commercial use.
  444. ;*      Adapted from KEYFLAGS (PC-World, Oct. 83, page 266) by Morton Kaplon
  445. ;*
  446. init    proc    near
  447.         call    testresident            ; see if handler already resident, 
  448.         jz      init_1                  ; ZF set = already resident -- print msg and exit
  449.         call    get_parms               ; see if reenabling NMI desired, set flag
  450.         jc      init_2                  ; if parm error, print usage message
  451.                                         ; else, install the handler
  452.         mov     al,nmi_int_no           ; interrupt number in AL
  453.         mov     ah,set_int_vec          ; funct. number for set int. vector
  454.         mov     dx,offset nmi_int_hdlr  ; offset of resident code
  455.         int     dosint                  ; set the vector
  456.         mov     dx,offset install_msg   ; print install message
  457.         mov     ah,prt_str              ;
  458.         int     dosint                  ;
  459.         mov     dx,offset end_nmi_int_hdlr ; set DX to end of resident code
  460.         int     27h                     ; dos terminate but stay resident func.
  461. init_1:
  462.         mov     dx,offset resident_msg  ; msg showing already installed
  463.         jmp     short init_3            ; print it and exit
  464. init_2:
  465.         mov     dx,offset usage_msg     ; general info. msg.
  466. init_3:
  467.         mov     ah,prt_str              ;
  468.         int     dosint                  ;
  469.         int     20h                     ; return to dos (nothing made resident)
  470. init    endp
  471.     page
  472. ;**************************************************************************
  473. ;* see if our handler is already resident -- zero flag set if it is.
  474. ;*
  475. ;* AX, BX, CX, SI, DI changed, ES preserved
  476. testresident proc near
  477.         push    es                      ;
  478.         mov     al,nmi_int_no           ; interrupt number in AL
  479.         call    get_vec                 ; interrupt vector returned in ES:BX
  480.         mov     orig_nmi_int_vec,bx     ; store IP of current servicer
  481.         mov     orig_nmi_int_vec[2],es  ; store CS of current servicer
  482.         mov     cx,len_nmi_int_hdlr     ; number of bytes to match
  483.         mov     si,offset nmi_int_hdlr  ; point DS:SI to our code
  484.         mov     di,bx                   ; make ES:DI point to current handler
  485.         cld                             ; auto increment
  486.         repe    cmpsb                   ; compare while equal - zero flag set on exit
  487.                                         ; if all bytes matched (already resident)
  488.         pop     es                      ;
  489.         ret
  490. testresident endp
  491.     page
  492. ;**************************************************************************
  493. ;* Get interrupt vector for interrupt number in AL.  On exit, ES:BX contain
  494. ;* CS:IP for vector.
  495. ;*
  496. ;* Only ES and BX changed
  497. get_vec proc near
  498.                 push    ax                      ; save entering value
  499.         push    ax                      ; save interrupt number requested
  500.         mov     ah,get_vers             ; dos get version function
  501.         int     dosint                  ; major version returned in AL, minor in AH
  502.         pop     bx                      ; restore int. number requested
  503.         cmp     al,2                    ; less than 2 = pre dos 2.0
  504.         jb      gv_direct               ; get vector directly
  505.         mov     al,bl                   ; move requested interrupt vector into AL
  506.         mov     ah,get_int_vec          ; dos get int. vector function
  507.         int     dosint                  ; CS:IP returned in ES:BX
  508.         pop     ax                      ;
  509.         ret
  510. gv_direct:                              ; get vector directly
  511.                                         ; first, convert number in BL to offset in BX
  512.         xor     bh,bh                   ; make sure BH = 0
  513.         shl     bx,1                    ; multiply by 4
  514.         shl     bx,1                    ;
  515.         mov     ax,int_vecs             ; point ES to segment for int. vectors
  516.         mov     es,ax                   ;
  517.         mov     ax,es:[bx+2]            ; get CS value into AX
  518.         mov     bx,es:[bx]              ; get IP value into BX
  519.         mov     es,ax                   ; mov CS value into ES
  520.         pop     ax                      ;
  521.         ret
  522. get_vec endp
  523.     page
  524. ;**************************************************************************
  525. ;* Scan command line for /R or /D installation option -- carry set
  526. ;* on exit if no valid parm.
  527. ;*
  528. ;* AX,BX,SI changed
  529. get_parms       proc near
  530.         mov     bx,offset cmd_ct        ; BX pts to number of cmd line chars
  531.         mov     si,[bx]                 ; get count
  532.         inc     bx                      ; point BX to 1st char
  533.         and     si,0ffh                 ; max. 127 chars. - set flags
  534.         jz      gp_err_exit             ; no parms, skip the rest
  535.         mov     byte ptr [bx][si],0     ; make command line null terminated
  536. gp_top_loop:
  537.         mov     al,[bx]                 ; get the char
  538.         or      al,al                   ; null?
  539.         je      gp_err_exit             ; if so, return error
  540.         cmp     al,spc                  ; space?
  541.         je      gp_bot_loop             ; yes, get another char
  542.         cmp     al,tab                  ; tab?
  543.         je      gp_bot_loop             ; yes, get another char
  544.         cmp     al,'/'                  ; see if possible /R or /D switch
  545.         jne     gp_err_exit             ; no, return error
  546.         call    ck_switches             ; check parm, carry set on error
  547.         jc      gp_err_exit             ; carry set, return error
  548.         jmp     gp_exit                 ;
  549. gp_bot_loop:
  550.         inc     bx                      ; point to next char
  551.         jmp     gp_top_loop             ; go get it
  552. gp_err_exit:
  553.         stc                             ; set carry to show error
  554. gp_exit:                                ; if got here by jump, carry is reset
  555.         ret
  556. ck_switches:                            ; ck parms ( BX pts to '/' )
  557.         inc     bx                      ; point to possible switch
  558.         mov     al,[bx]                 ; get char
  559.         cmp     al,'Z'                  ; check if possibly upper-case
  560.         jbe     ck_sw1                  ; no? continue
  561.         sub     al, 'a' - 'A'           ; make upper-case
  562. ck_sw1:
  563.         cmp     al,'R'                  ; reenable checking after parity error?
  564.         jne     ck_sw2                  ; no? continue
  565.         mov     reenable_flag,true      ; else, set flag
  566.         ret                             ; and return
  567. ck_sw2:
  568.         cmp     al,'D'                  ; disable checking after error?
  569.         je      ck_sw_exit              ; yes, return ok
  570.         stc                             ; else, set carry to show error
  571. ck_sw_exit:
  572.         ret
  573. get_parms       endp
  574. cseg    ends
  575. end     entry
  576. XA 6:            ; else, set carry to show error
  577. ck_sw_exit:
  578.         ret
  579. get_parms       endp
  580. cseg    e